#include "stdafx.h"
#include "Edit.h"

#include "SkCanvas.h"
#include "autotest/SerialSingleton.h"

Edit::Edit(View* parent)
	:View(parent)
	// , animation_(1, 500)
	, cursor_x_(0)
	, cursor_y_(0)
	, char_per_line_(0)
	, cursor_changed_(false)
	, ui_cursor_xpos_(0)
	, ui_cursor_ypos_(0)
	, mergin_left_(3)
	, mergin_top_(3)
	, mergin_right_(3)
	, mergin_bottom_(1)
	, ui_cursor_changed_(false)
	, select_(false)
	, select_start_(0)
	, select_end_(0)
	, auto_scroll_(true)
	, lines_(0)
	, lock_scroll_(false)
	, locked_start_line_(0)
	, count_ui_line_(0)
{
	font_ = std::shared_ptr<SkFont>(new SkFont(std::wstring(L"����"), 18));
	std::shared_ptr<EditLine> line = std::shared_ptr<EditLine>(new EditLine);
	line->start_line = 0;
	line->end_line = 0;
	text_.push_back(line);
}


Edit::~Edit()
{
}

bool Edit::paint(SkCanvas* canvas)
{
	paintBackground(canvas);

    if (getStatus() == STATUS_FOCUS)
	{
		paintFocus(canvas);
	}
    else
    {
	    paintBorder(canvas);
    }

    paintFrontground(canvas);
	// paintCursorBlink(canvas);
	return true;
}


bool Edit::paintBackground(SkCanvas* canvas)
{
	if (canvas)
	{
		canvas->FillRect(SkColor(50, 50, 50), 0, 0, Width(), Height());
		return true;
	}
	return false;
}

bool Edit::paintFrontground(SkCanvas* canvas)
{
	if (canvas)
	{
		canvas->setFont(*font_);
		int font_width = canvas->getFontWidth();
		if (font_width == 0)
		{
			return false;
		}
		int font_height = canvas->getFontHeight();

		if (font_width==0 || font_height==0)
		{
			SK_ASSERT(false || "zero");
			return false;
		}
		char_per_line_ = (Width() - mergin_left_ - mergin_right_) / font_width;
		lines_ = (Height() - mergin_top_ - mergin_bottom_) / font_height;
		// calc ui lines.
		int line_num = 0;
		for (std::list<std::shared_ptr<EditLine>>::iterator iter = text_.begin(); iter != text_.end(); ++iter)
		{
			if (*iter)
			{
				(*iter)->start_line = line_num;
				std::wstring str = (*iter)->str;
				if (char_per_line_ == 0)
				{
					SK_ASSERT(false || "zero");
					return false;
				}
				int text_placehold_line = str.length() / char_per_line_;
				if (str.length() % char_per_line_ != 0)
				{
					text_placehold_line++;
				}

				if (str.length() == 0) // no context
				{
					text_placehold_line = 1;
				}

				(*iter)->end_line = line_num + text_placehold_line - 1;

				line_num += text_placehold_line;
			}
		}
		count_ui_line_ = line_num;

		// show from m Line.
		int m_line = 0;
		if (auto_scroll_)
		{
			if (lines_ < line_num)
			{
				m_line = line_num - lines_;
			} 
		}

		if (lock_scroll_)
		{
			m_line = locked_start_line_;
		} 

		locked_start_line_ = m_line;

		line_num = 0;
		for (std::list<std::shared_ptr<EditLine>>::iterator iter = text_.begin(); iter != text_.end(); ++iter)
		{
			if (*iter)
			{
				std::wstring str = (*iter)->str;
				if (char_per_line_ == 0)
				{
					SK_ASSERT(false || "zero");
					return false;
				}

				int text_placehold_line = str.length() / char_per_line_;
				if (str.length() % char_per_line_ != 0)
				{
					text_placehold_line++;
				}

				if (str.length() == 0) // no context
				{
					text_placehold_line = 1;
				}

				for (int i = 0; i < text_placehold_line; i++)
				{
					if (line_num >= m_line)
					{
						std::wstring str_line = str.substr(i*char_per_line_, char_per_line_);
						//if ((Y() + (line_num - m_line) * font_height + mergin_top_) < 100)
						{
							ATLTRACE(L"Edit:: text Y: %d ***************\r\n", Y() + (line_num - m_line) * font_height + mergin_top_);
						}
						canvas->TextOut(str_line, X() + mergin_left_, Y() + (line_num - m_line) * font_height + mergin_top_ );
					}
					line_num++;
				}
			}
		}
		return true;
	}
	return false;
}

/*
bool Edit::paintBorder(SkCanvas* canvas)
{
	if (canvas)
	{
		canvas->drawRect(SkColor(98, 192, 255, 180), 0, 0, Width() - 1, Height() - 1);
		return true;
	}

	return false;
}
*/

bool Edit::paintHover(SkCanvas* canvas)
{
	if (canvas)
	{
		canvas->drawRect(SkColor(98, 192, 255, 200), 0, 0, Width() - 1, Height() - 1);
		return true;
	}
	return false;
}

bool Edit::paintFocus(SkCanvas* canvas)
{
	if (canvas)
	{
		canvas->drawRect(SkColor(98, 192, 255), 0, 0, Width() - 1, Height() - 1);
		return true;
	}

	return false;
}

void Edit::mouseEntry()
{
	ATLTRACE("[%s][%d]\r\n", __FUNCTION__, __LINE__);
	//HCURSOR cursor = ::GetCursor();
	::SetCursor(LoadCursor(NULL, IDC_IBEAM));

}

void Edit::mouseLeave()
{
	ATLTRACE("[%s][%d]\r\n", __FUNCTION__, __LINE__);

	::SetCursor(LoadCursor(NULL, IDC_ARROW));

}

void Edit::gotFocus()
{
/*
	if (!animation_.isAnimate())
	{
		animation_.start(this);
	}
	updateView();
*/
}

void Edit::loseFocus()
{
/*
	if (animation_.isAnimate())
	{
		animation_.cancel();
	}
*/
}

void Edit::appendText(const std::wstring& text)
{
	for (int index = 0; index < text.length(); ++index)
	{
		wchar_t ch = text.at(index);
		// Back Space
		if (ch == 0x08)
		{
			deleteChar(true);
		}
		else
		{
			cursor_changed_ = true;
			int i = 0;
			for (std::list<std::shared_ptr<EditLine>>::iterator iter = text_.begin(); iter != text_.end(); ++iter)
			{
				if (i == cursor_y_)
				{

					std::wstring str = (*iter)->str;
					(*iter)->str = str.substr(0, cursor_x_);
					if (ch == L'\r' || ch == L'\n')
					{
						std::shared_ptr<EditLine> new_line = std::shared_ptr<EditLine>(new EditLine);
						text_.insert(++iter, new_line);
						new_line->str = str.substr(cursor_x_, str.length() - cursor_x_);
						cursor_x_ = 0;
						cursor_y_++;
					}
					else
					{

						(*iter)->str += ch;

						(*iter)->str += str.substr(cursor_x_, str.length() - cursor_x_);
						cursor_x_++;
					}

					break;
				}
				i++;
			}
		}
	}

	updateView();
}

bool Edit::paintCursorBlink(SkCanvas* canvas)
{
	// TODO: ��BUG�� �����󣬵��õ������game over�ˡ�
	ATLTRACE("[%s][%d]\r\n", __FUNCTION__, __LINE__);

#if 0
	if (canvas)
	{
		canvas->setFont(*font_);
		int font_width = canvas->getFontWidth();
		if (font_width == 0)
		{
			return false;
		}
		int font_height = canvas->getFontHeight();
		
		if (ui_cursor_changed_)
		{
			updateStringPos();
			ui_cursor_changed_ = false;
		}
		if (cursor_changed_)
		{
			updateUIPos();
			cursor_changed_ = false;
		}

		int cursor_point_x = ui_cursor_xpos_ * font_width + mergin_left_;
		int cursor_point_y = ui_cursor_ypos_ * font_height + mergin_top_;
		ATLTRACE("drawLine [%s][%d][%d][%d]\r\n", __FUNCTION__, __LINE__, cursor_point_x, cursor_point_y);
		if (animation_.isAnimate())
		{
			if (animation_.getCalc() % 2 == 1)
			{
				canvas->drawLine(SkColor(255, 255, 255), cursor_point_x, cursor_point_y, cursor_point_x, cursor_point_y + font_height);
			}
		}

		return true;
	}
#endif
	return false;
}

bool Edit::processMouseEvent(MouseEvent& event)
{
	if (event.type == TYPE_TOUCH_WHEEL)
	{
		int n = event.param / WHEEL_DELTA;
		n = 0 - n;
		ATLTRACE("n:%d\r\n", n);
		int temp_line = locked_start_line_ + n * 3;
		if (temp_line<0)
		{
			temp_line = 0;
		}

		if (temp_line + lines_ >= count_ui_line_)
		{
			locked_start_line_ = count_ui_line_ - lines_;
			lock_scroll_ = false;
		}
		else
		{
			locked_start_line_ = temp_line;
			lock_scroll_ = true;
		}

		updateView();
		return true;
	}

	return false;
}

bool Edit::processKeyEvent(KeyEvent& event)
{

	return false;


	wchar_t ch = static_cast<wchar_t>(event.key_code);
	// Back Space
	if (ch == 0x08)
	{
		deleteChar(true);
	}
	else
	{
		cursor_changed_ = true;
		int i = 0;
		for (std::list<std::shared_ptr<EditLine>>::iterator iter = text_.begin(); iter != text_.end(); ++iter)
		{
			if (i == cursor_y_)
			{
				std::wstring str = (*iter)->str;
				(*iter)->str = str.substr(0, cursor_x_);
				if (ch == L'\r')
				{
					std::shared_ptr<EditLine> new_line = std::shared_ptr<EditLine>(new EditLine);
					text_.insert(++iter, new_line);
					new_line->str = str.substr(cursor_x_, str.length() - cursor_x_);
					cursor_x_ = 0;
					cursor_y_++;

					onChar(L'\n');
				}
				else
				{
					(*iter)->str += ch;
					(*iter)->str += str.substr(cursor_x_, str.length() - cursor_x_);
					cursor_x_++;
					onChar(ch);
				}

				break;
			}
			i++;
		}
	}

	cursor_changed_ = true;

	updateView();

	return false;
}

bool Edit::processRawKeyEvent(KeyEvent& event)
{

	return false;

	wchar_t ch = static_cast<wchar_t>(event.key_code);
	
	switch (event.key_code)
	{
	case 0x25: // left
		ui_cursor_xpos_--;
		ui_cursor_changed_ = true;
		break;
	case 0x26: // up
		ui_cursor_ypos_--;
		ui_cursor_changed_ = true;
		break;
	case 0x27: // right
		ui_cursor_xpos_++;
		ui_cursor_changed_ = true;
		break;
	case 0x28: // down
		ui_cursor_ypos_++;
		ui_cursor_changed_ = true;
		break;
	case 0x21: // page up
		break;
	case 0x22: // page down
		break;
	case 0x23: // end
		cursor_x_ = -1;
		cursor_changed_ = true;
		break;
	case 0x24: // home
		cursor_x_ = 0;
		cursor_changed_ = true;
		break;
	case 0x2E: // Del
		deleteChar(false);
		updateView();
		break;
	default:
		//ui_cursor_changed_ = false;
		return false;
	}

	return true;
}

bool Edit::updateUIPos()
{

	return false;

#if 0
	if (char_per_line_)
	{
		int i = 0;
		for (std::list<std::shared_ptr<EditLine>>::iterator iter = text_.begin(); iter != text_.end(); ++iter)
		{
			if (i == cursor_y_)
			{
				if (cursor_x_ == -1)
				{
					if (cursor_y_>0)
					{
						cursor_y_--;
						cursor_x_ = (*iter)->str.length();
					}
					else if (cursor_y_ == 0)
					{
						cursor_x_ = 0;
					}
				}


				ui_cursor_ypos_ = (cursor_x_ / (char_per_line_) + (*iter)->start_line);
				ui_cursor_xpos_ = cursor_x_ % (char_per_line_);

				return true;
			}
			i++;
		}
	}

	return false;
#endif
}

bool Edit::updateStringPos()
{
	cursor_changed_ = true;
	int i = 0;
	if (ui_cursor_xpos_ == -1)
	{
		if (ui_cursor_ypos_ > 0)
		{
			ui_cursor_ypos_--;
		}
		else
		{
			ui_cursor_xpos_ = 0;
		}
	}

	std::list<std::shared_ptr<EditLine>>::iterator iter = text_.begin();
	for (; iter != text_.end(); ++iter)
	{
		if (ui_cursor_ypos_ >= (*iter)->start_line && ui_cursor_ypos_ <= (*iter)->end_line)
		{
			cursor_y_ = i;
			if (ui_cursor_xpos_ == -1)
			{
				if (ui_cursor_ypos_ == (*iter)->end_line)
				{
					ui_cursor_xpos_ = (*iter)->str.length() % char_per_line_;
				}
				else
				{
					ui_cursor_xpos_ = char_per_line_ - 1;
				}
			}


			cursor_x_ = (ui_cursor_ypos_ - (*iter)->start_line) * char_per_line_ + ui_cursor_xpos_;
			if (cursor_x_ > (*iter)->str.length())
			{
				if (i+1 < text_.size()) // has next .
				{
					cursor_x_ = 0;
					cursor_y_++;
				} 
				else
				{
					cursor_x_ = (*iter)->str.length();
				}
			}
			return true;
		}
		i++;
	}

	std::list<std::shared_ptr<EditLine>>::reverse_iterator rIter = text_.rbegin();
	
	if (ui_cursor_ypos_ > (*rIter)->end_line)
	{
		cursor_y_ = text_.size() - 1;

		cursor_x_ = (ui_cursor_ypos_ - (*rIter)->start_line) * char_per_line_ + ui_cursor_xpos_;

		if (cursor_x_ > (*rIter)->str.length())
		{
			cursor_x_ = (*rIter)->str.length();
		}
		return true;
	}
	else if (ui_cursor_ypos_ < 0)
	{
		cursor_y_ = 0;
		iter = text_.begin();
		cursor_x_ = (ui_cursor_ypos_ - (*iter)->start_line) * char_per_line_ + ui_cursor_xpos_;

		if (cursor_x_ > (*iter)->str.length())
		{
			cursor_x_ = (*iter)->str.length();
		}
		return true;
	}

	// 
	
	return false;

}

bool Edit::deleteChar(bool back_space)
{
	if (select_)
	{
		return true;
	}

	if (back_space)
	{
		int i = 0;
		std::list<std::shared_ptr<EditLine>>::iterator pre_iter = text_.begin();
		for (std::list<std::shared_ptr<EditLine>>::iterator iter = text_.begin(); iter != text_.end(); ++iter,++i)
		{
			if (i == cursor_y_)
			{
				if (cursor_x_ == 0) // delete \r\n & combine prefix edit line
				{
					if (cursor_y_ != 0)
					{
						// (*pre_iter)->str = (*pre_iter)->str.substr(0, (*pre_iter)->str.length() - 2);
						cursor_x_ = (*pre_iter)->str.length();

						(*pre_iter)->str += (*iter)->str;
						text_.erase(iter);
						cursor_y_--;
					}
				}
				else
				{
					std::wstring str = (*iter)->str;
					(*iter)->str = (*iter)->str.substr(0, cursor_x_ - 1);
					(*iter)->str += str.substr(cursor_x_, str.length() - cursor_x_);
					cursor_x_--;
				}

				break;
			}

			pre_iter = iter;
		}
	} 
	else // delete
	{
		int i = 0;
		for (std::list<std::shared_ptr<EditLine>>::iterator iter = text_.begin(); iter != text_.end(); ++iter)
		{
			if (i == cursor_y_)
			{
				if (cursor_x_>=(*iter)->str.length()) // delete \r\n & combine next edit line
				{
					if (cursor_y_ + 1 < text_.size())
					{
						std::list<std::shared_ptr<EditLine>>::iterator next_iter = iter;
						next_iter++;
						// (*iter)->str = (*iter)->str.substr(0, (*iter)->str.length() - 2);
						(*iter)->str += (*next_iter)->str;
						text_.erase(next_iter);
					}
				} 
				else
				{
					std::wstring str = (*iter)->str;
					(*iter)->str = (*iter)->str.substr(0, cursor_x_);
					(*iter)->str += str.substr(cursor_x_ + 1, str.length() - cursor_x_ - 1);
				}

				break;
			}
		}

/*
		if (cursor_x_)
		{
		}
*/
	}
}


void Edit::goUp()
{

}

void Edit::goEnd()
{

}

void Edit::goHome()
{

}

void Edit::goDown()
{

}

void Edit::goLeft()
{

}

void Edit::goRight()
{

}

void Edit::onChar(wchar_t ch)
{
	SerialSingleton::getInstance().write(&ch, 1);
}
